package com.nevermore.floatbar

import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.widget.FrameLayout
import androidx.core.view.doOnNextLayout
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView

/**
 * @author xuchuanting
 * Create on 2021/4/14 17:17
 */
class FloatRvItemContainer : FrameLayout, FloatItemContract {

    constructor(context: Context) : this(context, null)

    constructor(context: Context, attributeSet: AttributeSet?) : this(context, attributeSet, 0)

    constructor(context: Context, attributeSet: AttributeSet?, defStyleAttr: Int) : super(
        context,
        attributeSet,
        defStyleAttr
    )

    private var recyclerView: RecyclerView? = null
    private var floatItemView: View? = null
    private var viewHolder: RecyclerView.ViewHolder? = null


    //    fun showItemFloat(position: Int): Boolean
    var showItemFloat: ((position: Int) -> Boolean)? = null

    var adapter: RecyclerView.Adapter<RecyclerView.ViewHolder>? = null


    override fun onFinishInflate() {
        super.onFinishInflate()
        val view = getChildAt(0)
        if (view is RecyclerView) {
            recyclerView = view
        }
    }


    var floatItemHeight = 0
    private var currentFloatItemPoi = -1

    fun observe() {
        recyclerView?.let {
            this.adapter = it.adapter
            val firstFloatPosition = findNexFloatItemPosition(0)
            ensureFloatItem(firstFloatPosition)
            bindFloatItem(firstFloatPosition)
        }
        recyclerView?.addOnScrollListener(object : RecyclerView.OnScrollListener() {

            override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
                super.onScrollStateChanged(recyclerView, newState)
            }

            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                super.onScrolled(recyclerView, dx, dy)
                val layoutManager = recyclerView.layoutManager
                if (layoutManager is LinearLayoutManager) {
                    val firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition()
                    if (showItemFloat(firstVisibleItemPosition)) {
                        updateFloatItem(firstVisibleItemPosition)
                    }

                    val nextItemPosition = firstVisibleItemPosition + 1
                    val itemCount = adapter?.itemCount ?: 0
                    if (nextItemPosition < itemCount) {
                        if (showItemFloat(nextItemPosition)) {
                            val preFloatItemPosition: Int =
                                findPreFloatItemPosition(firstVisibleItemPosition)
                            updateFloatItem(preFloatItemPosition)
                            val nextItemView = layoutManager.findViewByPosition(nextItemPosition)
                            nextItemView?.apply {
                                val top = nextItemView.top
                                if (top < floatItemHeight) {
                                    onRequestFloatItemTranslationY((top - floatItemHeight).toFloat())
                                }
                            }
                        } else {
                            onRequestFloatItemTranslationY(0f)
                        }
                    }
                }
            }
        })


    }

    private fun updateFloatItem(position: Int) {
        if (currentFloatItemPoi != position) {
            ensureFloatItem(position)
            bindFloatItem(position)
            currentFloatItemPoi = position
        }
    }

    /**
     * position 及之前该悬浮的item位置
     */
    private fun findPreFloatItemPosition(position: Int): Int {
        for (index in position downTo 0) {
            if (showItemFloat(index)) {
                return index
            }
        }
        return 0
    }

    private fun findNexFloatItemPosition(position: Int): Int {
        val itemCount = adapter?.itemCount ?: 0
        for (index in position until itemCount) {
            if (showItemFloat(index)) {
                return index
            }
        }
        return 0
    }

    private fun bindFloatItem(position: Int) {
        adapter?.apply {
            viewHolder?.let {
                bindViewHolder(it, position)
            }
        }
    }

    private fun ensureFloatItem(position: Int) {
        if (floatItemView == null) {
            adapter?.let {
                viewHolder =
                    it.createViewHolder(this@FloatRvItemContainer, it.getItemViewType(position))
                floatItemView = viewHolder?.itemView?.apply {
                    this@apply.doOnNextLayout {
                        floatItemHeight = it.measuredHeight
                    }
                }
                addView(floatItemView)
            }
        }
    }

    override fun showItemFloat(position: Int): Boolean {
        return showItemFloat?.invoke(position) ?: false
    }

    override fun onRequestFloatItemTranslationY(translationY: Float) {
        floatItemView?.translationY = translationY
    }

}